package com.northpool.operator.param;

import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
import com.northpool.operator.annotation.InputParam;
import com.northpool.operator.param.custom.DatasetParam;

import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

public class ParamTool {
    final Map<String, Parameter<?>> parameterMap;

    public ParamTool(Map<String, Parameter<?>> parameterMap) {
        this.parameterMap = parameterMap;
    }

    public Map<String, Parameter<?>> getParameterMap() {
        return parameterMap;
    }

    public Parameter<?> get(String ref) {
        return parameterMap.get(ref);
    }

    /**
     * 根据参数引用获取布尔类型的值（不存在返回 null）
     *
     * @throws IllegalArgumentException 参数存在但类型不匹配时抛出
     */
    public Boolean getBool(String ref) {
        if (ref == null) {
            return (Boolean) Parameter.Type.BOOL.defaultParameter().getValue();
        }

        Parameter<?> parameter = parameterMap.get(ref);
        if (parameter == null) {
            return null;
        }

        final Parameter.Type expectedType = Parameter.Type.BOOL;
        if (parameter.getType() == expectedType) {
            return (Boolean) parameter.getValue();
        } else {
            throw new IllegalArgumentException("参数 " + ref + " 类型不匹配，预期类型：" + expectedType);
        }
    }

    /**
     * 根据参数引用获取字符串类型的值（不存在返回 null）
     *
     * @throws IllegalArgumentException 参数存在但类型不匹配时抛出
     */
    public String getStr(String ref) {
        if (ref == null) {
            return Parameter.Type.STRING.defaultParameter().getStringValue();
        }

        Parameter<?> parameter = parameterMap.get(ref);
        if (parameter == null) {
            return null;
        }
        return parameter.getStringValue();
    }

    /**
     * 根据参数引用获取数字类型的值（不存在返回 null）
     *
     * @throws IllegalArgumentException 参数存在但类型不匹配时抛出
     */
    public BigDecimal getNumber(String ref) {
        Parameter<?> parameter = parameterMap.get(ref);
        if (parameter == null) {
            return null;
        }
        if (Parameter.Type.NUMBER.equals(parameter.getType())) {
            return (BigDecimal) parameter.getValue();
        } else {
            throw new IllegalArgumentException("参数 " + ref + " 不是数字类型");
        }
    }

    /**
     * 根据参数引用获取关联数据源ID
     *
     * @param ref 参数引用标识
     * @return 数据源ID，当参数不存在或类型不匹配时返回null
     * @throws IllegalArgumentException 当参数类型不是数据库类型时抛出
     */
    public String getDataSourceId(String ref) {
        Parameter<?> parameter = parameterMap.get(ref);
        if (parameter == null) {
            return null;
        }

        final Parameter.Type paramType = parameter.getType();
        if (Parameter.Type.DB.equals(paramType)) {
            Object value = parameter.getValue();
            if (value instanceof DatasetParam) {
                return ((DatasetParam) value).getDataSourceId();
            }
            Console.error("Invalid parameter value type for ref: {}", ref);
            throw new IllegalStateException("参数 " + ref + " 的值类型不匹配");
        }

        Console.error("非数据库类型参数访问: ref={}, type={}", ref, paramType);
        throw new IllegalArgumentException("参数 " + ref + " 不是数据库类型");
    }

    /**
     * 根据引用标识获取数据集参数
     *
     * @param ref 参数引用标识符，不可为null
     * @return 数据集参数对象，当参数不存在时返回null
     * @throws IllegalArgumentException 当参数存在但类型不匹配时抛出
     */
    public DatasetParam getDataset(String ref) {
        Parameter<?> parameter = parameterMap.get(ref);
        if (parameter == null) {
            return null;
        }

        // 使用==进行枚举常量比较
        if (parameter.getType() == Parameter.Type.DB || parameter.getType() == Parameter.Type.DATASET) {
            Object value = parameter.getValue();
            // 添加类型安全校验
            if (value instanceof DatasetParam) {
                return (DatasetParam) value;
            }
            throw new IllegalStateException("参数 " + ref + " 的值类型异常，预期类型: DatasetParam，实际类型: "
                    + (value != null ? value.getClass().getName() : "null"));
        }

        // 使用更具体的异常类型并携带完整信息
        throw new IllegalArgumentException("参数 " + ref + " 类型不匹配。预期类型: DB，实际类型: "
                + parameter.getType());
    }

    /**
     * 获取密钥参数
     *
     * @param ref 参数引用标识
     * @return 密钥字符串，当参数不存在时返回 null
     * @throws IllegalArgumentException 当参数存在但类型不匹配时抛出
     */
    public String getSecret(String ref) {
        final Parameter<?> parameter = parameterMap.get(ref);
        if (parameter == null) {
            return null;
        }

        final Parameter.Type type = Objects.requireNonNull(parameter.getType(),
                "参数类型不能为null");
        final Object value = parameter.getValue();

        if (type == Parameter.Type.SECRET) {
            if (value instanceof String) {
                return (String) value;
            }
            throw new ClassCastException("密钥参数值类型不匹配");
        }

        throw new IllegalArgumentException("参数 " + ref + " 类型不匹配。预期类型: SECRET，实际类型: "
                + parameter.getType());
    }

    public static Builder aBuilder() {
        return new Builder();
    }

    public static class Builder {
        private final Map<String, Parameter<?>> parameterMap = new LinkedHashMap<>();

        public Builder() {
        }

        public Builder add(String ref, Parameter<?> parameter) {
            if (parameter == null) {
                throw new IllegalArgumentException("参数不能为null");
            }
            parameterMap.put(ref, parameter);
            return this;
        }

        /**
         * 添加参数
         * @param inputParam 参数注解
         * @param value 参数值
         */
        public Builder add(InputParam inputParam, String value) {
            if (inputParam == null) {
                throw new IllegalArgumentException("参数不能为null");
            }

            Parameter<?> parameter = Parameter.Type.getEnumInstance(inputParam.type().name())
                    .map(type -> {
                        if (StrUtil.isEmpty(value)) {
                            return type.newParameter(inputParam.value(), true);
                        } else {
                            return type.newParameter(value, false);
                        }
                    })
                    .orElseThrow(() -> new IllegalArgumentException("未知参数类型: " + inputParam.type()));

            this.parameterMap.put(inputParam.ref(), parameter);
            return this;
        }

        public ParamTool build() {
            return new ParamTool(parameterMap);
        }
    }

}
